﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Collections;


namespace Devtm.ServiceModel.Discovery.Collection
{

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TKey">The type of the key.</typeparam>
    /// <typeparam name="TIndex">The type of the index.</typeparam>
    public class IndexUniqueCollection<T, TKey, TIndex> : TableCollection<T, TIndex>
    {

        private string nameProperty;


        internal Func<T, TIndex> _field { get; set; }
        public ITableCollection<T, TKey> list { get; set; }


        internal IndexUniqueCollection(
            ITableCollection<T, TKey> list, 
            Expression<Func<T, TIndex>> field)
            : base(field)
        {

            this._field = field.Compile();
            this.list = list;

            nameProperty = TableCollection.GetNameProperty(field);

            list.CollectionChanged += list_CollectionChanged;
            list.PropertyItemChanged += list_PropertyItemChanged;

            foreach (T item in list)
                    base.Add(item);

        }


        public override void Dispose()
        {
            base.Dispose();

            list.CollectionChanged -= list_CollectionChanged;
            list.PropertyItemChanged -= list_PropertyItemChanged;

        }

        void list_PropertyItemChanged(object sender, ItemPropertyChangedEventArgs<T> e)
        {

            if (e.PropertyName != nameProperty)
                return;

            TIndex f = _field(e.Item);
            bool c = ContainsKeyFrom(e.Item);

            if (c)
                base.Remove(e.Item);

            base.Add(e.Item);

        }



        void list_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            e.ApplyChange<T>
                (
                    item => base.Add(item),     // Add
                    item => base.Remove(item),  // remove
                    () => Clear()               // Clear
                );
        }


        #region Methods

        /// <summary>
        /// Adds the specified item to the the liste and return the item
        /// </summary>
        /// <param name="item">The item.</param>
        public override T Add(T item)
        {
            return list.Add(item);
        }


        /// <summary>
        /// Adds the range Item.
        /// </summary>
        /// <param name="items">The items.</param>
        public override void AddList(IList<T> items)
        {
            list.AddList(items);
        }


        /// <summary>
        /// Removes the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        public override void Remove(T item)
        {
            list.Remove(item);
        }


        /// <summary>
        /// Removes the item specified by the key and return the dettached element.
        /// </summary>
        /// <param name="key">The key.</param>
        public override void RemoveKey(TIndex key)
        {
            T item = this[key];
            list.Remove(item);
        }


        /// <summary>
        /// Removes the item specified by the key and return the dettached element.
        /// </summary>
        /// <param name="key">The key.</param>
        public override bool TryRemoveKey(TIndex key)
        {
            T item = this[key];
            return list.TryRemove(item);
        }


        /// <summary>
        /// Removes the item specified by the key and return the dettached element.
        /// </summary>
        /// <param name="key">The key.</param>
        public override bool TryRemove(T item)
        {
            return TryRemove(item);
        }


        /// <summary>
        /// Remplace l'élément à l'index spécifié.
        /// </summary>
        /// <param name="item">
        /// Nouvelle valeur de l'élément à l'index spécifié dans l'item
        /// </param>
        public override void Update(T item)
        {
            list.Update(item);
        }


        /// <summary>
        /// Supprime tous les éléments de la collection.
        /// </summary>
        public override void Clear()
        {
            foreach (var item in this)
                list.Remove(item);

        }

        #endregion
        
    }
}
